﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;
using System.Xml;
using System.Web.Routing;
using System.Collections;

namespace Subtle.Controllers
{
	public class SyndicationController : Controller
	{
		/// <summary>
		/// Rsd (Meta Weblog API)
		/// </summary>
		/// <returns></returns>
		public ActionResult Rsd()
		{
			var ns = XNamespace.Get("http://archipelago.phrasewise.com/rsd");

			return Xml(new XDocument(
						new XElement(ns + "service",
									 new XElement(ns + "engineName", "Subtle"),
									 new XElement(ns + "engineLink", "http://www.pieterg.com"),
									 new XElement(ns + "homePageLink", Url.RelativeToAbsolute(Url.RouteUrl("Default"))),
									 new XElement(ns + "apis",
												  new XElement(ns + "api",
															   new XAttribute("name", "MetaWeblog"),
															   new XAttribute("preferred", "true"),
															   new XAttribute("blogID", "0"),
															   new XAttribute("apiLink", Url.RelativeToAbsolute(Url.Content("~/Services/MetaWeblogAPI.ashx")))
													)
										)
							)
						), typeof(SyndicationController).FullName);
		}

		/// <summary>
		/// Xml
		/// </summary>
		/// <param name="xml"></param>
		/// <param name="etag"></param>
		/// <returns></returns>
		protected ActionResult Xml(XDocument xml, string etag)
		{
			return new XmlResult(xml, etag);
		}
	}

	/// <summary>
	/// Xml Result
	/// </summary>
	public class XmlResult : ActionResult
	{
		private readonly XDocument document;
		private readonly string etag;

		/// <summary>
		/// Initializes a new Xml Result
		/// </summary>
		/// <param name="document"></param>
		/// <param name="etag"></param>
		public XmlResult(XDocument document, string etag)
		{
			this.document = document;
			this.etag = etag;
		}

		/// <summary>
		/// Execute Result
		/// </summary>
		/// <param name="context"></param>
		public override void ExecuteResult(ControllerContext context)
		{
			if (etag != null)
				context.HttpContext.Response.AddHeader("ETag", etag);

			context.HttpContext.Response.ContentType = "text/xml";

			using (var xmlWriter = XmlWriter.Create(context.HttpContext.Response.OutputStream))
			{
				document.WriteTo(xmlWriter);
				xmlWriter.Flush();
			}
		}
	}

	/// <summary>
	/// Url Helper Extensions
	/// </summary>
	public static class UrlHelperExtensions
	{
		/// <summary>
		/// Absolute Action
		/// </summary>
		/// <param name="url"></param>
		/// <param name="action"></param>
		/// <param name="routeValues"></param>
		/// <returns></returns>
		public static string AbsoluteAction(this UrlHelper url, string action, object routeValues)
		{
			return AbsoluteActionUtil(url, url.Action(action, routeValues));
		}

		/// <summary>
		/// Absolute Action
		/// </summary>
		/// <param name="url"></param>
		/// <param name="action"></param>
		/// <returns></returns>
		public static string AbsoluteAction(this UrlHelper url, string action)
		{
			return AbsoluteActionUtil(url, url.Action(action));
		}

		/// <summary>
		/// Absolute Action
		/// </summary>
		/// <param name="url"></param>
		/// <param name="action"></param>
		/// <param name="controller"></param>
		/// <returns></returns>
		public static string AbsoluteAction(this UrlHelper url, string action, string controller)
		{
			return AbsoluteActionUtil(url, url.Action(action, controller));
		}

		/// <summary>
		/// Absolute Action
		/// </summary>
		/// <param name="url"></param>
		/// <param name="action"></param>
		/// <param name="controller"></param>
		/// <param name="routeValues"></param>
		/// <returns></returns>
		public static string AbsoluteAction(this UrlHelper url, string action, string controller, object routeValues)
		{
			return AbsoluteActionUtil(url, url.Action(action, controller, routeValues));
		}

		/// <summary>
		/// Relative To Absolute
		/// </summary>
		/// <param name="url"></param>
		/// <param name="relativeUrl"></param>
		/// <returns></returns>
		public static string RelativeToAbsolute(this UrlHelper url, string relativeUrl)
		{
			return AbsoluteActionUtil(url, relativeUrl);
		}

		/// <summary>
		/// Absolute Action Util
		/// </summary>
		/// <param name="url"></param>
		/// <param name="relativeUrl"></param>
		/// <returns></returns>
		private static string AbsoluteActionUtil(UrlHelper url, string relativeUrl)
		{
			var request = url.RequestContext.HttpContext.Request;
			Uri requestUrl = request.Url;
			string absoluteAction = string.Format("{0}://{1}{2}",
												  requestUrl.Scheme,
												  requestUrl.Authority,
												  relativeUrl);
			return absoluteAction;
		}

		/// <summary>
		/// Action Link with Array
		/// </summary>
		/// <param name="url"></param>
		/// <param name="action"></param>
		/// <param name="controller"></param>
		/// <param name="routeData"></param>
		/// <returns></returns>
		public static MvcHtmlString ActionLinkWithArray(this UrlHelper url, string action, string controller, object routeData)
		{
			string href = url.Action(action, controller);

			var rv = new RouteValueDictionary(routeData);
			var parameters = new List<string>();
			if (routeData != null)
			{
				foreach (var key in rv.Keys)
				{
					var propertyInfo = routeData.GetType().GetProperty(key);
					var value = propertyInfo.GetValue(routeData, null);
					var array = value as IEnumerable;
					if (array != null && !(array is string))
					{
						foreach (string val in array)
						{
							parameters.Add(string.Format("{0}={1}", key, val));
						}
					}
					else
					{
						parameters.Add(string.Format("{0}={1}", key, value));
					}
				}

			}

			string paramString = string.Join("&", parameters.ToArray());
			if (!string.IsNullOrEmpty(paramString))
			{
				href += "?" + paramString;
			}
			return MvcHtmlString.Create(href);
		}
	}
}
